#include "gpio_hal.h"
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_gpio.h"
#include "stm32f429xx.h"

typedef struct stm32_hal_gpio{
    void *port;
    uint16_t pin; 
}stm32_hal_gpio_t;

typedef struct stm32_gpio_map{
    const char *name;
    const char *use_type;
    stm32_hal_gpio_t gpio;
    gpio_device_pin_t dev_pin;
}stm32_gpio_map_t;

static const stm32_gpio_map_t stm32_gpio_map_table[] = {
    {"GPIOH_10", "led_red", {.port = GPIOH, .pin = GPIO_PIN_10}, .dev_pin = GPIO_DEVICE_NUM_0},
    {"GPIOH_11", "led_green", {.port = GPIOH, .pin = GPIO_PIN_11}, .dev_pin = GPIO_DEVICE_NUM_1},
    {"GPIOH_12", "led_blue", {.port = GPIOH, .pin = GPIO_PIN_12}, .dev_pin = GPIO_DEVICE_NUM_2},
    {"GPIOC_13", "key1_button", {.port = GPIOC, .pin = GPIO_PIN_13}, .dev_pin = GPIO_DEVICE_NUM_3},
    {"GPIOA_0", "key2_button", {.port = GPIOA, .pin = GPIO_PIN_0}, .dev_pin = GPIO_DEVICE_NUM_4},
};



static const stm32_gpio_map_t *get_stm32_gpio_map_entry(gpio_device_pin_t pin) {
    const int pin_map_num = DEVICE_ARRAY_SIZE(stm32_gpio_map_table);
    for (int i = 0; i < pin_map_num; i++) {
        if (stm32_gpio_map_table[i].dev_pin == pin) {
            return &stm32_gpio_map_table[i];
        }
    }

    return NULL;
}
static const stm32_gpio_map_t *get_stm32_gpio_map_entry_by_pin(uint16_t pin) {
    const int pin_map_num = DEVICE_ARRAY_SIZE(stm32_gpio_map_table);
    for (int i = 0; i < pin_map_num; i++) {
        if (stm32_gpio_map_table[i].gpio.pin == pin) {
            return &stm32_gpio_map_table[i];
        }
    }

    return NULL;
}

static IRQn_Type get_stm32_gpio_irqn(uint16_t pin) {
    switch (pin) {
        case GPIO_PIN_0: return EXTI0_IRQn;
        case GPIO_PIN_1: return EXTI1_IRQn;
        case GPIO_PIN_2: return EXTI2_IRQn;
        case GPIO_PIN_3: return EXTI3_IRQn;
        case GPIO_PIN_4: return EXTI4_IRQn;
        case GPIO_PIN_5:
        case GPIO_PIN_6:
        case GPIO_PIN_7:
        case GPIO_PIN_8:
        case GPIO_PIN_9: return EXTI9_5_IRQn;
        case GPIO_PIN_10:
        case GPIO_PIN_11:
        case GPIO_PIN_12:
        case GPIO_PIN_13:
        case GPIO_PIN_14:
        case GPIO_PIN_15: return EXTI15_10_IRQn;
        default: return (IRQn_Type)(-1);
    }
}

static int stm32_hal_gpio_init(gpio_device_pin_t pin, gpio_device_config_t *cfg) {
    const stm32_gpio_map_t *gpio_map = get_stm32_gpio_map_entry(pin);
    
    if (!gpio_map) {
        return -1;
    }
    if (gpio_map->gpio.port == GPIOA) {
        __HAL_RCC_GPIOA_CLK_ENABLE();
    }else if (gpio_map->gpio.port == GPIOB) {
        __HAL_RCC_GPIOB_CLK_ENABLE();
    }else if (gpio_map->gpio.port == GPIOC) {
        __HAL_RCC_GPIOC_CLK_ENABLE();  
    }else if (gpio_map->gpio.port == GPIOD) {
        __HAL_RCC_GPIOD_CLK_ENABLE();
    }else if (gpio_map->gpio.port == GPIOE) {
        __HAL_RCC_GPIOE_CLK_ENABLE();  
    }else if (gpio_map->gpio.port == GPIOF) {
        __HAL_RCC_GPIOF_CLK_ENABLE();
    }else if (gpio_map->gpio.port == GPIOG) {
        __HAL_RCC_GPIOG_CLK_ENABLE();
    }else if (gpio_map->gpio.port == GPIOH) {
        __HAL_RCC_GPIOH_CLK_ENABLE();
    }
    
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = gpio_map->gpio.pin;

    // 配置模式
    switch (cfg->mode) {
        case GPIO_DEVICE_MODE_INPUT:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            break;
        case GPIO_DEVICE_MODE_OUTPUT:
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
            break;
        case GPIO_DEVICE_MODE_OUTPUT_OD:
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
            break;
        case GPIO_DEVICE_MODE_INPUT_OD:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // STM32 没有直接支持 input-OD
            break;
        default:
            return -2;
    }

    // 配置上下拉
    if (cfg->pull_up_en == GPIO_PULLUP_ENABLE)
        GPIO_InitStruct.Pull = GPIO_PULLUP;
    else if (cfg->pull_down_en == GPIO_PULLDOWN_ENABLE)
        GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    else
        GPIO_InitStruct.Pull = GPIO_NOPULL;

    // 默认速度
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

    HAL_GPIO_Init(gpio_map->gpio.port, &GPIO_InitStruct);
    
    return 0;
}

static int stm32_hal_gpio_deinit(gpio_device_pin_t pin) {
    const stm32_gpio_map_t *gpio_map = get_stm32_gpio_map_entry(pin);
    
    if (!gpio_map) {
        return -1;
    }
    
    HAL_GPIO_DeInit(gpio_map->gpio.port, gpio_map->gpio.pin);
    
    return 0;
}

static int stm32_hal_gpio_get_level(gpio_device_pin_t pin) {
    const stm32_gpio_map_t *gpio_map = get_stm32_gpio_map_entry(pin);
    
    if (!gpio_map) {
        return -1;
    }
    GPIO_PinState level = HAL_GPIO_ReadPin(gpio_map->gpio.port, gpio_map->gpio.pin);
    return (level == GPIO_PIN_SET) ? GPIO_PIN_LEVEL_HIGH : GPIO_PIN_LEVEL_LOW;
}

static int stm32_hal_gpio_set_level(gpio_device_pin_t pin, gpio_device_pin_level_t level) {
    const stm32_gpio_map_t *gpio_map = get_stm32_gpio_map_entry(pin);
    
    if (!gpio_map) {
        return -1;
    }
    HAL_GPIO_WritePin(gpio_map->gpio.port, gpio_map->gpio.pin,(level == GPIO_PIN_LEVEL_HIGH) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    return 0;
}

static int stm32_hal_gpio_intr_enable(gpio_device_pin_t pin) {
    const stm32_gpio_map_t *gpio_map = get_stm32_gpio_map_entry(pin);
    if (!gpio_map) return -1;

    IRQn_Type irqn = get_stm32_gpio_irqn(gpio_map->gpio.pin);
    if (irqn == (IRQn_Type)(-1)) return -2;

    HAL_NVIC_SetPriority(irqn, 5, 0);  // 优先级根据你的系统 RTOS 或裸机配置调整
    HAL_NVIC_EnableIRQ(irqn);
    return 0;
}

static int stm32_hal_gpio_intr_disable(gpio_device_pin_t pin) {
    const stm32_gpio_map_t *gpio_map = get_stm32_gpio_map_entry(pin);
    if (!gpio_map) return -1;

    IRQn_Type irqn = get_stm32_gpio_irqn(gpio_map->gpio.pin);
    if (irqn == (IRQn_Type)(-1)) return -2;

    HAL_NVIC_DisableIRQ(irqn);
    return 0;
}

static int stm32_hal_gpio_set_intr_type(gpio_device_pin_t pin, gpio_device_intr_type_t type) {
    const stm32_gpio_map_t *gpio_map = get_stm32_gpio_map_entry(pin);
    if (!gpio_map) return -1;

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = gpio_map->gpio.pin;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    switch (type) {
        case GPIO_INTR_POSEDGE:
            GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
            break;
        case GPIO_INTR_NEGEDGE:
            GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
            break;
        case GPIO_INTR_ANYEDGE:
            GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
            break;
        default:
            return -2;  // 不支持低电平/高电平触发（STM32 仅支持边沿）
    }
    HAL_GPIO_Init(gpio_map->gpio.port, &GPIO_InitStruct);
    return 0;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    /* Prevent unused argument(s) compilation warning */
    /* NOTE: This function Should not be modified, when the callback is needed,
            the HAL_GPIO_EXTI_Callback could be implemented in the user file
    */
   const stm32_gpio_map_t * pin_map = get_stm32_gpio_map_entry_by_pin(GPIO_Pin);
   if (!pin_map) {
        return;
   }
    
//    printf("gpio_name : %s, pin_use_type : %s\r\n", pin_map->name, pin_map->use_type);
    gpio_driver_isr_handler(pin_map->dev_pin);

}



const gpio_hal_driver_ops_t gpio_stm32f4xx_hal_driver_ops = {
    .hal_gpio_init = stm32_hal_gpio_init,
    .hal_gpio_deinit = stm32_hal_gpio_deinit,
    .hal_gpio_get_level = stm32_hal_gpio_get_level,
    .hal_gpio_set_level = stm32_hal_gpio_set_level,
    .hal_gpio_intr_enable = stm32_hal_gpio_intr_enable,
    .hal_gpio_intr_disable = stm32_hal_gpio_intr_disable,
    .hal_gpio_set_intr_type = stm32_hal_gpio_set_intr_type,
};
